#if !defined _data_test_
#define _data_test_

#include <src/data/ParticleSet.h>
#include <src/data/OS_Multi_Array.h>

template <class data, std::size_t Dim = data::Dim> 
struct fill_data  
{
	data operator()()
	{
		OS_STATIC_CHECK(false); // you have to implement this test
	};
};

template <class data> 
struct fill_data<data,1>
{
	data operator()() {
		data A(4);
		for (OS_int i = 0; i<A.size();++i) {
			A[i] = i;
		};
		return A;
	};
};

template <class data> 
struct fill_data<data,2> 
{
	data operator()() {
		data A(3,4);
		for (OS_int i = 0; i<A.size(2);++i) {
			for (OS_int j = 0; j<A.size(1);++j)
				A[i][j] = i+j;
		};
		return A;
	};
};
template <class data> 
struct fill_data<data,3> 
{
	data operator()() {
		data A(2,3,4);
		for (OS_int i = 0; i<A.size(3);++i) {
			for (OS_int j = 0; j<A.size(2);++j)
				for (OS_int k = 0; k<A.size(1);++k)
					A[i][j][k] = i+j+k;
		};
		return A;
	};
};


template <class data, std::size_t Dim = data::Dim>
struct array_test {
	array_test() {
		OS_STATIC_CHECK(false); // you have to implement this test
	};
};
template <class array_type_1>
	struct array_test<array_type_1,1> {
		array_test (){
			typedef typename array_type_1::Boundary_type Boundary_type;
			std::cout << std::endl << " ---------------------------------------------------" << std::endl;
			std::cout << std::endl << " --------Starting array_type_example 1D-------" << std::endl;
			std::cout << std::endl << " --------type of data : " << array_type_1::get_name() << Boundary_type::get_name() << std::endl;

			array_type_1 A = fill_data<array_type_1>()();
			array_type_1 A_zero(A);
			A_zero.assign(0.);
			bool logical = false;


			std::cout << std::endl << " Basic assignation and creation test" << std::endl;

			array_type_1 A_copy(A);
			std::cout << "One dimensional A{4}" << A << std::endl;

			std::cout << std::endl << " reference testing" << std::endl;
			typedef typename array_type_1::reference reference;
			reference test_reference = A[0];
			typedef typename array_type_1::value_type value_type;
			value_type test_value_type = A[0];

			std::cout << std::endl << " Algebra operations test" << std::endl;
			array_type_1 A1(A);
			A1 = 2.*A + A;
			std::cout << "A1 = 2.*A + A. A1 is  " << A1 << std::endl;
			std::cout << std::endl << " should be equal to 3*A " << 3.*A << std::endl;
			logical = A1 == 3.*A;
			OS_DYNAMIC_CHECK(logical == true, "array_test : logical test A1 == 3.*A failed in 1D");

			std::cout << " test memory access : A is  now " << A << std::endl;
			logical = A == A_copy;
			std::cout << " should be equal to " <<  A_copy << " : " << ( logical ? "true" : "false") << std::endl;
			OS_DYNAMIC_CHECK(logical == true, "array_test 1D : logical test A == A_copy failed");


			A = A-A;
			std::cout << "A = A - A. A is now " << A << std::endl;
			std::cout << std::endl << " should be equal to zero " << A_zero << std::endl;
			logical = A == A_zero;
			OS_DYNAMIC_CHECK(logical == true, "array_test 1D : logical test A == A_zero failed in 1D");

			std::cout << std::endl << " std compatibility " << std::endl;
			A = -A_copy;
			std::cout << std::endl << " std::sorting the vector  " << A << std::endl;
			std::sort(A.begin(),A.end());
			std::cout << " verifying sort " << A << std::endl;
			for (OS_int i = 0; i<A.size()-1;++i)
					logical &= A[i] < A[i+1];
			OS_DYNAMIC_CHECK(logical == true, "array_test 1D : verifying sort failed in 1D");

			logical = A < A;
			std::cout << std::endl << " comparing. A < A should be false " << ( logical ? "true" : "false") << std::endl;
			OS_DYNAMIC_CHECK(logical == false, "array_test 1D : logical test A < A failed");

			std::cout << std::endl << " --------End array_type_example 1D-------" << std::endl;
			std::cout << std::endl << " ---------------------------------------------------" << std::endl;
		};
	};
///////////////////////////////////////////////////////

template <class array_type_2>
	struct array_test<array_type_2,2> {
		array_test() {
			typedef typename array_type_2::value_type array_type_1;
			typedef typename array_type_2::reference reference;
			std::cout << std::endl << " ---------------------------------------------------" << std::endl;
			std::cout << std::endl << " --------Starting array_type_example 2D-------" << std::endl;

			array_test<array_type_1>();
			array_type_1 A = fill_data<array_type_1>()();
			array_type_1 A_zero(4);
			array_type_1 A_one(4);
			A_one.assign(1.);
			A_zero.assign(0.);


			std::cout << std::endl << " example for " << typeid(array_type_2).name()<< std::endl << std::endl ;
			std::cout << std::endl << " --------type of data : " << typeid(array_type_2::Boundary_type).name()<< std::endl;

			std::cout << std::endl << "Two dimensional Basic assignation and creation test" << std::endl;
			array_type_2 B = fill_data<array_type_2>()();
			array_type_2 B_zero(B);
			B_zero.assign(0.);

			bool logical = false;
			array_type_2::iterator it_B= B.begin();


			std::cout << std::endl << "Two dimensional B{3,4}" << std::endl << B << std::endl;
			array_type_2 B_copy(B);
			array_type_2 B_copy_2 = B;

			std::cout << std::endl << " reference testing" << std::endl;
			typedef typename array_type_2::reference reference;
			reference test_reference = B[0];
			typedef typename array_type_2::value_type value_type;
			array_type_1 T1 = B[0];
			T1.assign(0.);
			std::cout << "down (one) dimensional assignation T1 = B[0]. T1.assign(0.) is : " << std::endl << T1 << std::endl;
			std::cout << " test memory access : B is  now " << B << std::endl;
			logical = B == B_copy;
			std::cout << " should be equal to " <<  B_copy << " : " << ( logical ? "true" : "false") << std::endl;
			OS_DYNAMIC_CHECK(logical == true, "array_test 2D : T1 = B[0] failed");
			std::cout << " should be equal to " <<  B_copy_2 << " : " << ( logical ? "true" : "false") << std::endl;
			OS_DYNAMIC_CHECK(logical == true, "array_test 2D : T1 = B[0] failed");

			array_type_1 A3; 
			A3 = B[2]-B[1];
			std::cout << "down (one) dimensional assignation A3 = B[2]-B[1]. A3 is : " << std::endl << A3 << std::endl;
			std::cout << "should be equal to one : " << A_one << std::endl;
			logical = A3 == A_one;
			OS_DYNAMIC_CHECK(logical == true, "array_test 2D : logical test A3 == A_one failed");

			std::cout << " test memory access : B is  now " << B << std::endl;
			logical = B == B_copy;
			std::cout << " should be equal to " <<  B_copy << " : " << ( logical ? "true" : "false") << std::endl;
			OS_DYNAMIC_CHECK(logical == true, "array_test 2D : logical test B == B_copy failed");


			B[2] = A+A;
			std::cout << "upper (one )dimensional assignation B[2] = A+A. B is now  : " << std:: endl << B << std::endl;
			logical = B[2] == 2.*A;
			std::cout << " should be equal to 2.*A " <<  2.*A << " : " << ( logical ? "true" : "false") << std::endl;
			OS_DYNAMIC_CHECK(logical == true, "array_test 2D : logical test B[2] == 2.*A failed");

			array_type_2 B_test(B);

			B[0] *= 3.;
			std::cout << "B is now " << B << std::endl << "B_copy is " << B_copy<< std::endl;
			B_test[0] = (B[0]+B_copy[0])/2.;
			B_test[1] = (B[1]+B_copy[1])/2.;
			B_test[2] = (B[2]+B_copy[2])/2.;
			logical = B_test == (B+B_copy)/2.;
			OS_DYNAMIC_CHECK(logical == true, "array_test 2D : B_test == (B+B_copy)/2. failed");

			B = B_copy;
			std::cout << "B = B_copy. B is now " << B << std::endl;
			B = B + 2.*B;
			std::cout << "B = 2.*B + B. B is now " << B << std::endl;
			std::cout << std::endl << " should be equal to 3.*B_copy : " << 3.*B_copy << std::endl;
			logical = B == 3.*B_copy;
			OS_DYNAMIC_CHECK(logical == true, "array_test 2D : logical test B == 3.*B_copy failed");

			
			B = B-B;
			std::cout << "B = B-B. B is now " << B << std::endl;
			std::cout << std::endl << " should be equal to zero " << B_zero << std::endl;
			logical = B == B_zero;
			OS_DYNAMIC_CHECK(logical == true, "array_test 2D : logical test B == B_zero failed");

			logical = B < B;
			std::cout << std::endl << " comparing. B < B should be false " << ( logical ? "true" : "false") << std::endl;
			OS_DYNAMIC_CHECK(logical == false, "array_test 2D : logical test B < B failed");



			std::cout << std::endl << " --------End array_type_example 2D-------" << std::endl;
			std::cout << std::endl << " ---------------------------------------------------" << std::endl;

		};
	};

template <class array_type_3>
	struct array_test<array_type_3,3> {
		array_test() {

			std::cout << std::endl << " ---------------------------------------------------" << std::endl;
			std::cout << std::endl << " --------Starting array_type_example 2D-------" << std::endl;
			std::cout << std::endl << " --------type of data : " << array_type_3::get_name() << array_type_3::Boundary_type::get_name() << std::endl;
			typedef typename array_type_3::reference reference;
			typedef typename array_type_3::value_type array_type_2;
			typedef typename array_type_2::value_type array_type_1;
			array_test<array_type_1>();
			array_test<array_type_2>();

			array_type_1 A=fill_data<array_type_1>()();
			array_type_1 A_zero(4);
			bool logical = false;
			A_zero.assign(0.);


			array_type_2 B=fill_data<array_type_2>()();
			array_type_2 B_zero(B);
			B_zero.assign(0.);

			array_type_2::iterator it_B= B.begin();
			array_type_2 B_copy(B);


			array_type_3 C=fill_data<array_type_3>()();

			std::cout << std::endl << " Three Dimensional C{2,3,4}" << std::endl << C;
			std::cout << std::endl << " C[0][0] is " << C[0][0] << " A is " << A << std::endl;
			logical = C[0][0] == A;
			std::cout << std::endl << " Verify C[0][0] == A :" << std::endl <<  (logical ? "true" : "false") << std::endl;
			OS_DYNAMIC_CHECK(logical == true, "array_test 3D : logical test C[0][0] == A failed");
			C[0][0] = C[0][0]-2.*A;
			std::cout << "down (two) dimensional assignation C[0][0] -= 2.*A. C is now  : " << std::endl << C << std::endl;
			logical = C[0][0] == -A;
			std::cout << std::endl << " Verify C[0][0] == -A :" << std::endl <<  (logical ? "true" : "false") << std::endl;
			OS_DYNAMIC_CHECK(logical == true, "array_test 3D : logical test C[0][0] == -A failed");
			B = C[0];
			std::cout << "upper (two) dimensional assignation B = C[0] : B is now  : " << std::endl << B << std::endl;
			logical = B[0] == -A;
			std::cout << std::endl << " Verify B[0] == -A :" << std::endl <<  (logical ? "true" : "false") << std::endl;
			OS_DYNAMIC_CHECK(logical == true, "array_test 3D : logical test B[0] == -A failed");


			std::cout << std::endl << " --------End array_type_example 3D-------" << std::endl;
			std::cout << std::endl << " ---------------------------------------------------" << std::endl;
		};

	};


struct data_test {
	data_test ();
};
#endif